package org.noahsark.core.action;

import java.lang.reflect.ParameterizedType;

import org.noahsark.core.domainmodel.BaseEntity;
import org.noahsark.core.exception.BusinessException;
import org.noahsark.core.exception.SystemException;

/**
 * 提供实体的增删改. 使用对话作用域，在多次操作及子页面之间共状态。 实体增删改的基类，默认使用对话作用域。主要提供实体增删改方法，处理业务增删改方法
 * 中抛出的业务异常，以及获取实体和变换实体方法。
 * 
 * @param <E> E extends BaseEntity
 */
public abstract class BaseCrudAction<E extends BaseEntity> extends BaseAction {

    private E instance;
    private Class<E> entityClass;

    private boolean managed = false;

    /**
     * 子类重写. 用于设置当前操作实体，并对实体进行clone，这样页面的所有操作都是基于 vo的，不会导致数据库改变，只有调用create,update,remove后才会更新数据库。
     */
    public abstract void initEntity();

    /**
     * 子类重写. 用于清空查询条件.
     */
    public void resetSearch() {
    }

    /**
     * 是否可以修改
     */
    public void isAllowUpdate() {
        isAllowUpdate(instance);
    }

    /**
     * 是否可以修改
     */
    public void isAllowUpdate(Object inst) {
        if (!ActionListenerControl.instance().isContinueFlag()) {
            return;
        }

//        if (inst instanceof BaseEffectiveEntity) {
//            if (((BaseEffectiveEntity) inst).isEffective()
//                    || ((BaseEffectiveEntity) inst).isExpired()) {
//                ActionListenerControl.instance().notCoutinue();
//                addErrorMessage("effective.error.cantBeEdit");
//            }
//        }
    }

    /**
     * 是否可以Terminate
     */
    public void isAllowTerminate() {
        isAllowTerminate(instance);
    }

    /**
     * 是否可以Terminate
     */
    public void isAllowTerminate(Object inst) {
        if (!ActionListenerControl.instance().isContinueFlag()) {
            return;
        }

//        if (inst instanceof BaseEffectiveEntity) {
//            if (((BaseEffectiveEntity) inst).getEffectiveTo() != null
//                    && !DateUtils.clearTime(((BaseEffectiveEntity) inst).getEffectiveTo()).after(
//                            DateUtils.today())) {
//                ActionListenerControl.instance().notCoutinue();
//                addErrorMessage("effective.error.cantBeTerminated");
//            }
//        }
    }

    /**
     * 在页面上调用，用于创建实体. 使用模板方法设计模式，如何创建实体由子类的
     * createEntity()方法提供。该方法处理子类createEntity()方法中抛出的BusinessException
     * 及BusinessException的子异常，将异常消息放入jsf messages中，其他类型的异常不处理。 创建实体成功后调用cleanEntity()，可以继续创建新的实体。
     */
    public void create() {
        try {
            createEntity();
            // cleanEntity(); // 连续添加 2012-11-05 去掉连续添加功能
        } catch (BusinessException e) {
            BusinessException be = (BusinessException) e;
            addErrorMessage(be.getMessage());
            ActionListenerControl.instance().notCoutinue();
        } catch (SystemException e) {
            addErrorMessage(e.getErrorCode());
            ActionListenerControl.instance().notCoutinue();
        }
    }

    /**
     * 子类重写 被create方法调用，用于调用service的创建实体方法，成功后添加消息. servcice抛出的异常 一般不在方法内处理，由create方法统一处理。
     * 
     * @throws BusinessException service方法中抛出的异常，service方法也可以不抛出异常。
     */
    protected abstract void createEntity() throws BusinessException;

    /**
     * 在页面上调用，用于更新实体. 使用模板方法设计模式，如何更新实体由子类的
     * updateEntity()方法提供。该方法处理子类updateEntity()方法中抛出的BusinessException
     * 及BusinessException的子异常，将异常消息.ges中，其他类型的异常不处理。
     */
    public void update() {
        try {
            updateEntity();
        } catch (BusinessException e) {
            BusinessException be = (BusinessException) e;
            addErrorMessage(be.getMessage());
            ActionListenerControl.instance().notCoutinue();
        } catch (SystemException e) {
            addErrorMessage(e.getErrorCode());
            ActionListenerControl.instance().notCoutinue();
        }
    }

    /**
     * 子类重写 被update方法调用，用于调用service的更新实体方法，成功后添加消息. servcice抛出的异常 一般不在方法内处理，由create方法统一处理。
     * 
     * @throws BusinessException service方法中抛出的异常，service方法也可以不抛出异常。
     */

    protected abstract void updateEntity() throws BusinessException;

    /**
     * 在页面上调用，用于删除实体. 使用模板方法设计模式，如何删除实体由子类的
     * removeEntity()方法提供。该方法处理子类removeEntity()方法中抛出的BusinessException
     * 及BusinessException的子异常，将异常消息放入jsf messages中，其他类型的异常不处理。 删除实体成功后调用cleanEntity()。
     */
    public void remove() {
        try {
            removeEntity();
            cleanEntity();
        } catch (BusinessException e) {
            BusinessException be = (BusinessException) e;
            addErrorMessage(be.getMessage());
            ActionListenerControl.instance().notCoutinue();
        } catch (SystemException e) {
            addErrorMessage(e.getErrorCode());
            ActionListenerControl.instance().notCoutinue();
        }
    }

    /**
     * 子类重写 被remove方法调用，用于调用service的更新实体方法，成功后添加消息. servcice抛出的异常 一般不在方法内处理，由remove方法统一处理。
     * 
     * @throws BusinessException service方法中抛出的异常，service方法也可以不抛出异常。
     */
    protected abstract void removeEntity() throws BusinessException;

    /**
     * to prepare add.
     */
    public void cleanEntity() {
        managed = false;
        setInstance(null);
        initEntity();
    }

    /**
     * 选中行后调用，调用initEntity方法将选中的实体out 必须是被管理的po，否则抛出异常.
     * 
     * @param entity entity
     */
    public void setEntity(E entity) {//
//        if (!getEntityManager().contains(entity)) {
//            throw new RuntimeException(" must be po");
//        }
        managed = true;
        setInstance(entity);
        initEntity();
    }

//    private EntityManager getEntityManager() {
//        return (EntityManager) Component.getInstance("entityManager");
//    }

    /**
     * 判断当前操作实体是新增还是编辑，主要用于页面按钮显示控制，比如 新增时编辑按钮不显示.
     * 
     * @return boolean in em
     */
    public boolean isManaged() {
        return managed;
    }

    /**
     * 被initEntity方法调用，用于获取当前操作实体. 新增：getEntityClass().newInstance()，如果是BspEntity的子类自动设置bspCode
     * 编辑：由setEntity设置
     * 
     * getInstance获取的是new或数据库对象，不会获取到页面操作的对象，页面操作的对象 是clone出来的，没有执行setEntity将clone对象放入instance。
     * 
     * @return E entity
     */
    public E getInstance() {
        if (instance == null) {
            initInstance();
        }
        return instance;
    }

    protected void setInstance(E instance) {
        this.instance = instance;
    }

    private void initInstance() {
        setInstance(createInstance());
    }

    /**
     * 创建新的实例，如果是bsp级实体还要设置bspcode属性.
     * 
     * @return E newInstance
     */
    private E createInstance() {
        if (getEntityClass() != null) {
            try {
                instance = getEntityClass().newInstance();
                return instance;
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        } else {
            return null;
        }
    }

    @SuppressWarnings("unchecked")
    private Class<E> getEntityClass() {
        if (entityClass == null) {
            entityClass = (Class<E>)((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
        }
        return entityClass;
    }
}
